﻿#if NET45_OR_GREATER
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using zijian666.Converts.Abstractions;
using zijian666.Converts.Core;

namespace zijian666.Converts.Json;

/// <summary>
/// <seealso cref="JsonElement"/> 翻译器
/// </summary>
public class JsonElementTranslator : JsonConverter, ITranslator
{
    /// <inheritdoc />
    public override bool CanConvert(Type type) => type == typeof(object);
    /// <inheritdoc />
    public bool CanTranslate(Type type) => type == typeof(JToken);
    /// <inheritdoc />
    public object? Translate(IConvertContext context, object? input)
    {
        var conv = context.Settings.GetConvertor<DynamicObject>(context);
        return Translate(context, conv, input);
    }
    /// <summary>
    /// 翻译值
    /// </summary>
    /// <param name="context">转换上下文</param>
    /// <param name="convertor">转换器</param>
    /// <param name="input">输入值</param>
    /// <returns></returns>
    public object? Translate(IConvertContext context, IConvertor<DynamicObject>? convertor, object? input)
    {
        var element = input as JToken;

        if (element is null)
        {
            return input;
        }

        switch (element.Type)
        {
            case JTokenType.Array:
                var list = new ArrayList();
                foreach (var item in (JArray)element)
                {
                    _ = list.Add(Translate(context, convertor, item));
                }
                return Dynamic(context, convertor, list.ToArray());
            case JTokenType.Integer:
                return Dynamic(context, convertor, element.Value<long>());
            case JTokenType.Float:
                return Dynamic(context, convertor, element.Value<decimal>());
            case JTokenType.String:
                return Dynamic(context, convertor, element.Value<string>());
            case JTokenType.Boolean:
                return Dynamic(context, convertor, element.Value<bool>());
            case JTokenType.Null:
            case JTokenType.Undefined:
                return Dynamic(context, convertor, DBNull.Value);
            case JTokenType.Date:
            case JTokenType.Guid:
            case JTokenType.Bytes:
            case JTokenType.Uri:
            case JTokenType.TimeSpan:
                return Dynamic(context, convertor, element.Value<object>());
            case JTokenType.Object:
                var expando = new Dictionary<string, object?>();
                foreach (var item in (JObject)element)
                {
                    expando.Add(item.Key, Translate(context, convertor, item.Value?.Value<object>()));
                }
                return Dynamic(context, convertor, expando);
            default:
                return Dynamic(context, convertor, null);
        }
    }

    /// <summary>
    /// 将 <paramref name="value"/> 转为动态类型
    /// </summary>
    public object? Dynamic(IConvertContext context, IConvertor<DynamicObject>? convertor, object? value)
    {
        if (convertor is not null)
        {
            var result = convertor.Convert(context, value);
            if (result.Success)
            {
                return result.Value;
            }
        }
        return value;
    }
    public override bool CanWrite => false;
    /// <inheritdoc/>
    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) => throw new NotImplementedException();
    /// <inheritdoc/>
    public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
    {
        var element = serializer.Deserialize(reader);
        return Translate(ConvertContext.Current ?? new ConvertContext(), element);
    }

}

#endif